home *** CD-ROM | disk | FTP | other *** search
- /*
- * rtstrat.c -- strategy map data for rtrees.
- */
- #include "tmp/c.h"
-
- #include "utils/rel.h"
-
- #include "storage/bufmgr.h"
- #include "storage/bufpage.h"
- #include "storage/page.h"
-
- #include "access/isop.h"
- #include "access/istrat.h"
- #include "access/rtree.h"
-
- RcsId("$Header: /private/postgres/src/access/index-rtree/RCS/rtstrat.c,v 1.3 1991/02/27 19:32:47 mao Exp $");
-
- /*
- * Note: negate, commute, and negatecommute all assume that operators are
- * ordered as follows in the strategy map:
- *
- * left, left-or-overlap, overlap, right-or-overlap, right, same,
- * contains, contained-by
- *
- * The negate, commute, and negatecommute arrays are used by the planner
- * to plan indexed scans over data that appears in the qualificiation in
- * a boolean negation, or whose operands appear in the wrong order. For
- * example, if the operator "<%" means "contains", and the user says
- *
- * where not rel.box <% "(10,10,20,20)"::box
- *
- * the planner can plan an index scan by noting that rtree indices have
- * an operator in their operator class for negating <%.
- *
- * Similarly, if the user says something like
- *
- * where "(10,10,20,20)"::box <% rel.box
- *
- * the planner can see that the rtree index on rel.box has an operator in
- * its opclass for commuting <%, and plan the scan using that operator.
- * This added complexity in the access methods makes the planner a lot easier
- * to write.
- */
-
- /* if a op b, what operator tells us if (not a op b)? */
- static StrategyNumber RTNegate[RTNStrategies] = {
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy
- };
-
- /* if a op_1 b, what is the operator op_2 such that b op_2 a? */
- static StrategyNumber RTCommute[RTNStrategies] = {
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy
- };
-
- /* if a op_1 b, what is the operator op_2 such that (b !op_2 a)? */
- static StrategyNumber RTNegateCommute[RTNStrategies] = {
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy
- };
-
- /*
- * Now do the TermData arrays. These exist in case the user doesn't give
- * us a full set of operators for a particular operator class. The idea
- * is that by making multiple comparisons using any one of the supplied
- * operators, we can decide whether two n-dimensional polygons are equal.
- * For example, if a contains b and b contains a, we may conclude that
- * a and b are equal.
- *
- * The presence of the TermData arrays in all this is a historical accident.
- * Early in the development of the POSTGRES access methods, it was believed
- * that writing functions was harder than writing arrays. This is wrong;
- * TermData is hard to understand and hard to get right. In general, when
- * someone populates a new operator class, the populate it completely. If
- * Mike Hirohama had forced Cimarron Taylor to populate the strategy map
- * for btree int2_ops completely in 1988, you wouldn't have to deal with
- * all this now. Too bad for you.
- *
- * Since you can't necessarily do this in all cases (for example, you can't
- * do it given only "intersects" or "disjoint"), TermData arrays for some
- * operators don't appear below.
- *
- * Note that if you DO supply all the operators required in a given opclass
- * by inserting them into the pg_opclass system catalog, you can get away
- * without doing all this TermData stuff. Since the rtree code is intended
- * to be a reference for access method implementors, I'm doing TermData
- * correctly here.
- *
- * Note on style: these are all actually of type StrategyTermData, but
- * since those have variable-length data at the end of the struct we can't
- * properly initialize them if we declare them to be what they are.
- */
-
- /* if you only have "contained-by", how do you determine equality? */
- static uint16 RTContainedByTermData[] = {
- 2, /* make two comparisons */
- RTContainedByStrategyNumber, /* use "a contained-by b" */
- 0x0, /* without any magic */
- RTContainedByStrategyNumber, /* then use contained-by, */
- CommuteArguments /* swapping a and b */
- };
-
- /* if you only have "contains", how do you determine equality? */
- static uint16 RTContainsTermData[] = {
- 2, /* make two comparisons */
- RTContainsStrategyNumber, /* use "a contains b" */
- 0x0, /* without any magic */
- RTContainsStrategyNumber, /* then use contains again, */
- CommuteArguments /* swapping a and b */
- };
-
- /* now put all that together in one place for the planner */
- static StrategyTerm RTEqualExpressionData[] = {
- (StrategyTerm) RTContainedByTermData,
- (StrategyTerm) RTContainsTermData,
- NULL
- };
-
- /*
- * If you were sufficiently attentive to detail, you would go through
- * the ExpressionData pain above for every one of the seven strategies
- * we defined. I am not. Now we declare the StrategyEvaluationData
- * structure that gets shipped around to help the planner and the access
- * method decide what sort of scan it should do, based on (a) what the
- * user asked for, (b) what operators are defined for a particular opclass,
- * and (c) the reams of information we supplied above.
- *
- * The idea of all of this initialized data is to make life easier on the
- * user when he defines a new operator class to use this access method.
- * By filling in all the data, we let him get away with leaving holes in his
- * operator class, and still let him use the index. The added complexity
- * in the access methods just isn't worth the trouble, though.
- */
-
- static StrategyEvaluationData RTEvaluationData = {
- RTNStrategies, /* # of strategies */
- (StrategyTransformMap) RTNegate, /* how to do (not qual) */
- (StrategyTransformMap) RTCommute, /* how to swap operands */
- (StrategyTransformMap) RTNegateCommute, /* how to do both */
- NULL, /* express left */
- NULL, /* express overleft */
- NULL, /* express over */
- NULL, /* express overright */
- NULL, /* express right */
- (StrategyExpression) RTEqualExpressionData, /* express same */
- NULL, /* express contains */
- NULL /* express contained-by */
- };
-
- /*
- * Okay, now something peculiar to rtrees that doesn't apply to most other
- * indexing structures: When we're searching a tree for a given value, we
- * can't do the same sorts of comparisons on internal node entries as we
- * do at leaves. The reason is that if we're looking for (say) all boxes
- * that are the same as (0,0,10,10), then we need to find all leaf pages
- * that overlap that region. So internally we search for overlap, and at
- * the leaf we search for equality.
- *
- * This array maps leaf search operators to the internal search operators.
- * We assume the normal ordering on operators.
- */
- static StrategyNumber RTOperMap[RTNStrategies] = {
- RTOverLeftStrategyNumber,
- RTOverLeftStrategyNumber,
- RTOverlapStrategyNumber,
- RTOverRightStrategyNumber,
- RTOverRightStrategyNumber,
- RTOverlapStrategyNumber,
- RTContainsStrategyNumber,
- RTContainedByStrategyNumber
- };
-
- StrategyNumber
- RelationGetRTStrategy(r, attnum, proc)
- Relation r;
- AttributeNumber attnum;
- RegProcedure proc;
- {
- return (RelationGetStrategy(r, attnum, &RTEvaluationData, proc));
- }
-
- bool
- RelationInvokeRTStrategy(r, attnum, s, left, right)
- Relation r;
- AttributeNumber attnum;
- StrategyNumber s;
- Datum left;
- Datum right;
- {
- return (RelationInvokeStrategy(r, &RTEvaluationData, attnum, s,
- left, right));
- }
-
- RegProcedure
- RTMapOperator(r, attnum, proc)
- Relation r;
- AttributeNumber attnum;
- RegProcedure proc;
- {
- StrategyNumber procstrat;
- RegProcedure newproc;
- StrategyMap strategyMap;
-
- procstrat = RelationGetRTStrategy(r, attnum, proc);
- strategyMap = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(r),
- RTNStrategies,
- attnum);
-
- return (strategyMap->entry[RTOperMap[procstrat - 1] - 1].procedure);
- }
-